#include "log.h"
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include "printf.h"

char log_buffer[LOG_BUFFER_SIZE] = {0};
bool log_is_disable = false;
uint16_t log_fmt_set[LOG_LEVEL_NUM] = {0};

/**
 * @brief 设置日志输出所有格式
 * 
 */
void log_set_all_fmt(void)
{
    log_disable();
    for (uint8_t i = 0; i < LOG_LEVEL_NUM; i++)
    {
        log_fmt_set[i] = LOG_FMT_ALL;
    }
    log_enable();
}

/**
 * @brief 设置日志输出格式
 * 
 * @param level 要设置的日志等级
 * @param type 设置的格式
 */
void log_set_fmt(uint8_t level, uint16_t type)
{
    log_fmt_set[level] |= type;
}

/**
 * @brief 清除特定的日志输出格式
 * 
 * @param level 要清除的日志等级
 * @param type 清除的格式
 */
void log_clear_fmt(uint8_t level, uint16_t type)
{
    log_fmt_set[level] &= ~type;
}

uint8_t log_fmt_is_set(uint8_t level, LogFmtType type)
{
    return log_fmt_set[level] & type;
}

void log_init(void)
{
    extern void log_port_init(void);
    log_port_init();
    LOG_INFO("Log init success");
}

/**
 * @brief 输出日志
 * 
 * @param level 日志等级
 * @param file 文件名
 * @param func 函数名
 * @param line 行号
 * @param format 格式化字符串
 * @return uint8_t 0:成功 其他失败
 */
uint8_t log_output(LogMode mode, uint8_t level, const char *file, const char *func,
                    const long line, const char *format, ...)
{
    uint16_t len = 0;
    if (log_is_disable)
    {
        return 4;
    }
    va_list args;
    va_start(args, format);
    // 判断并输出日志等级
    if (log_fmt_is_set(level, LOG_FMT_LEVEL))
    {
        const char *level_str = NULL;
        switch (level)
        {
        case LOG_LEVEL_DEBUG:
            level_str = "DEBUG";
            break;
        case LOG_LEVEL_INFO:
            level_str = "INFO";
            break;
        case LOG_LEVEL_WARN:
            level_str = "WARN";
            break;
        case LOG_LEVEL_ERROR:
            level_str = "ERROR";
            break;
        case LOG_LEVEL_FATAL:
            level_str = "FATAL";
            break;
        default:
            level_str = "UNKNOWN";
            break;
        }
        len = snprintf(log_buffer, LOG_BUFFER_SIZE, "[%s] ", level_str);
    }
    // 输出时间
    if (log_fmt_is_set(level, LOG_FMT_TIME))
    {
        extern uint32_t log_port_get_time(void);
        len += snprintf(log_buffer + len, LOG_BUFFER_SIZE - len, "[%ld] ", log_port_get_time());
    }
    // 输出文件名
    if (log_fmt_is_set(level, LOG_FMT_FILE))
    {
        len += snprintf(log_buffer + len, LOG_BUFFER_SIZE - len, "%s|", file);
    }
    // 输出函数名
    if (log_fmt_is_set(level, LOG_FMT_FUNC))
    {
        len += snprintf(log_buffer + len, LOG_BUFFER_SIZE - len, "%s():", func);
    }
    // 输出行号
    if (log_fmt_is_set(level, LOG_FMT_LINE))
    {
        len += snprintf(log_buffer + len, LOG_BUFFER_SIZE - len, "%ld: ", line);
    }
    len += vsnprintf(log_buffer + len, LOG_BUFFER_SIZE - len, format, args);    // 输出剩余内容
    // extern uint32_t log_port_get_time(void);
    // len = snprintf(log_buffer, LOG_BUFFER_SIZE, "[%s] [%ld]%s|%s():%ld: ", level_str, log_port_get_time(),file, func, line);
    // len += vsnprintf(log_buffer + len, LOG_BUFFER_SIZE - len, format, args);
    va_end(args);
    if (mode == LOG_MODE_NORMAL) {
        extern uint8_t log_port_output(uint8_t *data, uint16_t size);
        return log_port_output((uint8_t *)log_buffer, len);
    } else {
        extern uint8_t log_port_output_IT(uint8_t *data, uint16_t size);
        return log_port_output_IT((uint8_t *)log_buffer, len);
    }
}

/**
 * @brief 关闭日志
 * 
 */
void log_disable(void)
{
    log_is_disable = true;
}

/**
 * @brief 开启日志
 * 
 */
void log_enable(void)
{
    log_is_disable = false;
}
